#ifndef L_SYSTEM_H
#define L_SYSTEM_H

#endif

#include <math.h>
#include <iostream>

#include <string>

#include "Module.h"

#ifdef __gnu_linux__
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#elif _WIN32
#include <windows.h>
#include <ole2.h>
#include <ocidl.h>
#include <olectl.h>
#include "glsl.h"
#include <gl/GL.h>
#include "glut.h"
#endif

const float DEG2RAD = 3.14159/180.;

/*The original L-System class. Takes an edge length, a divergence angle, has capacity for single and multi-production L-Systems.
	The L-System is encoded as a simple string, and production applications is more or less string analysis. Possible improvments:
		-Encode the L-System some other way, not relying on std::string, iterators and char symbols to speed up production AND turtle analysis*/
class L_System
{
	public:
		float edgeLength, theta;
		std::string returnList, production, buildList;
		std::vector<std::string> productionList;

		L_System();
		L_System(std::string, std::string, float, float);
		L_System(std::string, std::vector<std::string>, float, float);
		virtual void propogate(int);
};

/*A struct to encapsulate a list of productions for a given symbol in a stochastic L-System with their respective probabilities of application*/
struct edgeProduction
		{
			std::vector<std::string> productions;
			float *weights;
		};

/*Extends the original L-System, using edgeProductions instead of strings. First use of a vector*/
class Stochastic_L_System : public L_System
{
	public:
		
		std::vector<edgeProduction> productionList;
		edgeProduction *production;

		Stochastic_L_System(std::string i, edgeProduction *p, float eL, float t);
		Stochastic_L_System(std::string i, std::vector<edgeProduction> productions, 
								float eL, float t);
		void propogate(int);
};

/*L-System specified by vectors of modules. See module class for more*/
class Parametric_L_System : public L_System
{
	public:
		std::vector<Module> returnList, buildList;
		std::vector<Production> productionList;

		Parametric_L_System();
		Parametric_L_System(float, float, std::vector<Module>, std::vector<Production>);
		void propogate(int);
};

/*Turtle for regular L-System analysis. Takes strings for analysis. Can specify 3D or 2D analysis. Requires information from the L_system currently
	under analysis. Possible improvements:
		-Remove the pointer to the L-System, instead copying necessary information from a given L-System in based on need.
			-Is this the best idea? It would be nice to know which L-System the turtle is currently SUPPOSED to be drawing, but we would have to update manually
			-It's only there to get edge length and angle information. We would still have to pass that information manually when we change what we're drawing.
			-Nah
		-Interpretation might occur faster if we weren't fooling with std::string, an iterator and a switch statement. I'm sure those are pretty slow tools.*/
class Turtle
{
	public:
		float X, Y, Z;
		float phi[3];

		bool in3D;

		L_System *lsys;
		std::string symbols;

		Turtle();
		Turtle(float, float, float, L_System*);
		Turtle(float, float, float, float, float, float, L_System*);
		void stir(std::string);
};

/*Hit the performance wall pretty quickly on parametric systems. Streamlining the Module class and moving away from the vector<Template> might speed parametric
systems up enough to make them interactable.*/
class Parametric_Turtle : public Turtle
{
	public:
		std::vector<Module> symbols;

		Parametric_Turtle();
		Parametric_Turtle(float, float, float, L_System*);
		Parametric_Turtle(float, float, float, float, float, float, L_System*);

		void stir(std::vector<Module>);
};

void drawLine3D();
void drawLeaf3D();

void drawCircle();
void drawLine();
